/*
 * @Author: your name
 * @Date: 2021-08-25 15:48:07
 * @LastEditTime: 2024-10-25 17:23:02
 * @LastEditors: huanggang you@example.com
 * @Description: In User Settings Edit
 * @FilePath: \common_code\watchdog\src\watchdog.h
 */
#ifndef __WATCHDOG_H__
#define __WATCHDOG_H__

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>

// 只有下面四项需要用户修改
#define MAX_LEN (64)
#define ALIVE_CHECK_MAX_ITEM 30
#define ALIVE_CHECK_DEAD_LEN 3

typedef enum
{
    STATE_INIT = 0, // 被监控对象最开始处于的状态,一旦有心跳则会改变
    STATE_ALIVE,    // 被监控对象是活动的
    STATE_DEAD,     // 被监控对象已停止
    STATE_DEADING,  // 被监控对象濒死,下次监测时如果还没心跳则进入死亡
} ALIVE_STATE_E;

typedef enum
{
    TYPE_HAS_DEADING = 0, // 有濒死状态,出现心跳停止后，则可容忍一个检测周期，再做判断
    TYPE_NO_DEADING,      // 没有濒死状态，只要出现心跳停止，则直接判定为离线
} ALIVE_TYPE_E;

// 引入外部的打印函数,这样方便接入其他日志系统
typedef int (*print_func_t)(const char *format, ...);

typedef struct
{
    // 被监控对象名字，出异常时打印使用
    char name[MAX_LEN];
    // 被监测对象的现在状态
    ALIVE_STATE_E state;
    // 被监测对象的上次状态
    ALIVE_STATE_E last_state;
    ALIVE_TYPE_E type;
    // 处在各个状态的时间
    unsigned int total_init_sec;
    unsigned int total_alive_sec;
    unsigned int total_dead_sec;
    // 最近一次处于死亡状态的时刻
    unsigned int last_dead_sec_arr[ALIVE_CHECK_DEAD_LEN];
    // 最近一次检测被监控对象的时间
    unsigned int last_sec;
    // 被监控对象总的死亡次数
    unsigned int total_dead_cnt;
    // 被监控对象总的濒死次数,可以反映被监控对象的稳定性
    unsigned int total_deading_cnt;
    // 用来判断被监控对象心跳,循环计数就可
    unsigned int last_heart_cnt;
    unsigned int curr_heart_cnt;
    // 被监测对象的检测周期，在检测时会更新各个状态
    unsigned int check_period;
} alive_item_t;

typedef struct
{
    unsigned int inited;
    // 监控的线程/进程数目
    int cnt;
    // 保存打印接口
    print_func_t print;
    // 保存每个线程/进程的配置信息
    alive_item_t items[ALIVE_CHECK_MAX_ITEM];
} alive_conf_t;

// 放在一个周期运行的循环里面，比如看门狗线程
// second必须是一个顺序变化的数,建议1秒变化1
void alive_check_items(unsigned int second);

// 初始化该模块,可以指定打印函数,方便接入外部日志系统,为空默认为printf
void alive_check_init(print_func_t print);

// 添加被监控对象,period为该监控对象的检测周期
int alive_check_add(const char *item_name, int period, ALIVE_TYPE_E type);

// 打印某个或所有被监控对象的状态信息,当输入为NULL时打印所有的被监控对象信息
void alive_check_print_states(char *item_name);

// 获取指定名字的被监控对象的状态信息
int alive_check_get_state(char *item_name, alive_item_t *item);

// 需要添加在被监控的对象正常运行的流程中,index为被监控对象的索引值
void alive_check_beat(int index);

#endif /* __WATCHDOG_H__ */
